package br.ufpe.cin.camid.core.objects;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import br.ufpe.cin.camid.core.lifecycle.ManagedObjectInvocationException;

public class InvocationTask {

	
	public InvocationTask() {
		
	}

	public Object call(Object entity, String method, Object[] params) 
	{
		boolean evaluated = false;
		Object result = null;

		Method[] methods = entity.getClass().getMethods();
		
		try
		{
			for(Method m : methods)
			{
				if(method.equals(m.getName()))
				{
					Class<?>[] concreteParamDefs = m.getParameterTypes();
					if((params == null && concreteParamDefs.length == 0) || (params.length == concreteParamDefs.length))
					{
						boolean match = true;
						for(int i = 0; i < concreteParamDefs.length && match; i++)
						{
							match = concreteParamDefs[i].isAssignableFrom(params[i].getClass());
						}
						if(match)
						{
							result = m.invoke(entity, params);
							evaluated = true;
						}
					}
				}
				if(evaluated)
					break;
			}
		} 
		catch (IllegalArgumentException e) 
		{
			throw new ManagedObjectInvocationException("Invocation error: wrong argument passed on method call for object of type " 
					+ entity.getClass().getCanonicalName() , e);
		} 
		catch (IllegalAccessException e) 
		{
			throw new ManagedObjectInvocationException(String.format(
					"Invocation error: method %s for object of type %s has access restrictions",
					method,
					entity.getClass().getCanonicalName()), e);
		} 
		catch (InvocationTargetException e) 
		{
			throw new ApplicationException(e.getCause());
		}
		if(evaluated == false)
		{
			throw new ManagedObjectInvocationException(String.format(
					"Invocation error: could not find a match for method %s for object of type %s ", 
					method,
					entity.getClass().getCanonicalName()));
		}

		return result;
	}
}
